package model.drawServer.Implement;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.Queue;

import model.drawPanel.DrawOrder_ADD;
import model.drawPanel.Order;

class ClientProxy {
    private Socket s;
	private ObjectInputStream in;
	private ObjectOutputStream out;
	private InetAddress addr;
	private DatagramSocket udp;
	private DrawRoom room;
	private int roomID;
	private boolean isIniting = false;
	private Thread sendThread;
	private  Queue<Order> bufferList;
	public ClientProxy(Socket s){
		bufferList = new LinkedList<Order>();
		try{
			this.s = s;
			this.in = new ObjectInputStream(s.getInputStream());
			this.out =new ObjectOutputStream(s.getOutputStream());
			addr = s.getInetAddress();
			try {
				roomID = (Integer)in.readObject();
			} catch (NumberFormatException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			udp = new DatagramSocket();
			startSendThread();
			startTCPreceive();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public void addToRoom(DrawRoom room){
		this.room = room;
	}
	public int getRoomID(){
		return roomID;
	}
	
	public InetAddress getAddr() {
		return addr;
	}
	private void startSendThread(){
		 sendThread = new Thread(new Runnable(){
			public void run(){
				while(true){
					if(bufferList.size()==0){
						try {
							synchronized (sendThread) {
								sendThread.wait();
							
							}
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}else{
						send_(bufferList.poll());
					}
				}
			}
		});
		 sendThread.start();
		
	}
	private void send_(Order order){
			/*if(order.getClass().getName().equals("model.drawPanel.IniteOrder")||(order.getClass().getName().equals("model.drawPanel.DrawOrder_ADD") &&
				((DrawOrder_ADD)order).getEntity().getClass().getName().equals("model.drawPanel.entitys.Picture"))){
			// too biger ->use tcp
			try {
				out.writeObject(order);
				return;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}*/
		byte[] data =object_to_byte(order);
		if(data.length>1024){
			try {
				out.writeObject(order);
				return;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		DatagramPacket packet  = new DatagramPacket(data,data.length);
		packet.setPort(DrawServer.drawClientUdpPort);
		try {
			packet.setAddress(addr);
			udp.send(packet);
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	 catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public void send(Object order){
			bufferList.offer((Order)order);
			synchronized (sendThread) {
				sendThread.notify();
			}
			
	}
		private byte[] object_to_byte (Object object){
			ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
			try {
				ObjectOutputStream buffers = new ObjectOutputStream(byteBuffer);
				buffers.writeObject(object);
				return byteBuffer.toByteArray();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		return null;
		}
		private boolean isObjectTooBiger(Object o){
			byte[] temp = object_to_byte(o);
			if(temp.length >= 1024){
				return true;
			}
			return false;
		}
		public void startTCPreceive(){
			Thread tcp = new Thread(new Runnable(){
				public void run(){
					while(true){
						try {
							Order order =(Order)in.readObject();
							room.receiveMsg(order, addr);
							
						} catch (IOException e) {
							e.printStackTrace();
							exite();
							return;
						} catch (ClassNotFoundException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
			});
			tcp.start();
		}
	private void exite(){
			try {
				in.close();
				out.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			room.userLeave(addr);
			return;
	}
}
	/*class TCPReceiveThread implements Runnable{
		ObjectInputStream in;
		ObjectOutputStream out;
		InetAddress addr;
		Socket s;
		public TCPReceiveThread(){
				this.s =s;
				addr = s.getInetAddress();
		}
		public void run(){
			System.out.println(" TCPReceiveThread is run");
			try {
				in = new ObjectInputStream(s.getInputStream());
				out = new ObjectOutputStream(s.getOutputStream());
				try {
					in.readObject();
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	 			
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			while(true){
				try {
					Order order =(Order)in.readObject();
					receiveMsg(order, addr);
					System.out.println("receive a tcp in server  ");
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					continue;
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					continue;
				}
			}
		}
	}*/
